<?php

namespace common\service;


use common\exception\LogicException;
use common\model\EntityModel;
use common\model\EpisodeAllocationModel;
use common\model\StepWorkflowModel;
use common\model\TaskModel;
use common\model\UserModel;
use support\ErrorCode;
use think\Exception;
use think\module\Module;

/**
 * 内部审核工作流服务
 */
class InsideTaskReviewWorkflowService extends ReviewWorkflowService
{

    /**
     * 查询任务审批流
     * @param int $taskId
     * @param int $userId
     * @return array
     * @throws \Exception
     */
    public function selectReview(int $taskId, int $userId): array
    {
        /**
         *
         * 内部任务审核流匹配用户
         *
         * 1. 查询任务相关信息
         * 2. 查询任务使用的审核流
         * 3. 查询审核流需要的角色信息
         * 4. 查询出租户里的这些角色成员信息
         * 5. 进行特定规则匹配
         *
         */
        $taskFields = [
            "t.id", "t.name", "t.code", "t.project_id", "t.tenant_id", "t.entity_id", "t.step_id", "t.assignee", "t.executor", 't.department_id', 't.step_category_id',
            'e.step_workflow_id', 'e.initial_episode_code'
        ];
        $taskData = model(EntityModel::class)->alias("e")->join('task t on e.id = t.entity_id')->field($taskFields)->where(['t.id' => $taskId])->find();
        if (empty($taskData)) {
            throw new LogicException("can`t found [task/related review_workflow]", ErrorCode::TASK_NOT_FOUND);
        }
        // 任务审核流配置信息
        $projectReviewWorkflowRelation = $this->getTaskReviewWorkflowRelationConfig($taskId, $taskData['project_id'], $taskData['step_workflow_id'], $taskData['step_id']);

        //审批流查询
        $reviewFilter = [
            'id' => $projectReviewWorkflowRelation['review_workflow_id'],
            'active' => "yes",
            'is_deleted' => "no",
        ];
        list($nodesData, $promoter, $reviewers) = $this->getParsedWorkflow($reviewFilter);

        // 自己的用户信息
        $userInfo = teamones_request('teamones-im', 'user/get_my_user_info', null)['data'];

        // 审核流需要的角色列表查询
        $reviewers = array_column($reviewers, 'role');

        // 审核人字典
        $reviewersMap = [];
        // role 角色为 组员 artist headman, 以任务的step_category_id 去获取人员列表
        $stepCategoryId = 0;
        // 其他 role 角色 通过 role_id 匹配 project_member 中匹配的人员
        $reviewerByStepCategory = [];
        $reviewerByRoleCodes = [];

        foreach ($reviewers as $reviewer) {
            if (in_array($reviewer, ['artist', 'headman'])) {
                $stepCategoryId = $taskData['step_category_id'];
                $reviewerByStepCategory[] = $reviewer;
            } else {
                $reviewerByRoleCodes[] = $reviewer;
            }
        }

        $userList = [];
        // 1.通过 step_category_id 去获取人员列表
        if (!empty($reviewerByStepCategory)) {
            $userConfigList = ProjectTeamService::getInstance()->getTeamConfigList($taskData['project_id'], 0, 0, $stepCategoryId);
            $userTeamIdList = array_column($userConfigList, 'id');

            if (!empty($userTeamIdList)) {
                $teamId = array_shift($userTeamIdList);
                $userListByStepCategory = ProjectTeamService::getInstance()->getTeamUserList($taskData['project_id'], $teamId, [1, 100], $reviewerByStepCategory);
                if (!empty($userListByStepCategory['rows'])) {
                    $userList = array_merge($userList, $userListByStepCategory['rows']);
                }
            }
        }

        // 2.通过 role_id 匹配 project_member 中匹配的人员
        if (!empty($reviewerByRoleCodes)) {
            $userListByRoleCode = ProjectTeamService::getInstance()->getTeamUserList($taskData['project_id'], 0, [1, 100], $reviewerByRoleCodes);
            if (!empty($userListByRoleCode['rows'])) {
                $userList = array_merge($userList, $userListByRoleCode['rows']);
            }
        }

        // 3.格式化数据
        if (!empty($userList)) {
            foreach ($userList as $user) {
                foreach ($user['role_list'] ?? [] as $userRole) {
                    if (!isset($reviewersMap[$userRole['code']])) {
                        $reviewersMap[$userRole['code']] = [
                            'role_name' => $userRole['name'],
                            'role_code' => $userRole['code'],
                            'user_info' => [],
                            'skip' => 0,
                            'user_id' => 0,
                        ];
                    }
                    $reviewersMap[$userRole['code']]['user_info'][] = [
                        'id' => $user['user_info']['id'],
                        'name' => $user['user_info']['name'],
                        'avatar' => $user['user_info']['avatar'],
                        'phone' => $user['user_info']['phone'],
                        'email' => $user['user_info']['email'],
                        'union_id' => $user['user_info']['union_id'],
                    ];
                }
            }
        }

        return [
            "review_workflow" => $nodesData,
            "matched_data" => [
                'promoter' => $promoter,
                'reviewers' => array_values($reviewersMap),
                'self_info' => $userInfo,
            ],
        ];
    }

    /**
     * 获取多个任务的属性
     * @param $taskIds
     * @return array
     * @throws \Exception
     */
    public function getMultipleTaskAttr($taskIds)
    {
        if (empty($taskIds)) {
            return [];
        }
        // 1、找到当前任务所属实体的 module_id
        $taskData = model(TaskModel::class)->where(['id' => ['IN', implode(',', $taskIds)]])->field('id,entity_id,entity_module_id,step_id')->cache(C('database.default_query_cache_time'))->select();

        if (empty($taskData)) {
            // 任务id不存在
            throw new LogicException('task not found', ErrorCode::TASK_NOT_FOUND);
        }

        $moduleIds = [];
        $entityIds = [];
        foreach ($taskData as $taskDataItem) {
            $moduleIds[$taskDataItem['entity_module_id']] = $taskDataItem['entity_module_id'];
            $entityIds[$taskDataItem['entity_id']] = $taskDataItem['entity_id'];
        }

        // 2、查找当前任务实体属性自定义字段映射数据
        $attributeRuleMapByCode = FieldService::getInstance()->getMultipleEntityAttributeCustomFieldsMapping($moduleIds, 'code');

        // 3、查找当前实体所属的工序流id
        $entityData = model(EntityModel::class)->where(['id' => ['IN', join(',', $entityIds)]])->field('id,step_workflow_id,json')->select();

        // 生成当前任务的工序流唯一属性标识
        return StepWorkflowService::getInstance()->multipleGenerateWorkflowStepDocAttrStr($entityData, $attributeRuleMapByCode, $taskData);
    }

    /**
     * 获取审核流程进度
     * @param $param
     * @param int $userId
     * @return array
     * @throws Exception
     */
    public function getUserReviewWorkFlow($param, int $userId)
    {
        $stepWorkflowId = $param['filter']['step_workflow_id'];
        $projectId = $param['filter']['project_id'];
        $taskId = $param['filter']['task_ids'];
        $stepId = $param['filter']['step_id'];
        $attrStr = $param['filter']['attr_str'] ?? "";

        $task = model(TaskModel::class)->where(['id' => ['IN', $taskId]])->field('entity_id,step_category_id')->cache(C('database.default_query_cache_time'))->select();
        //只能同集提交
        $episodeId = 0;
        if (!empty($task)) {
            $entity = model(EntityModel::class)->field('initial_episode_code')->find($task[0]['entity_id']);
            if (!empty($entity)) {
                $episodeId = model(EntityModel::class)->where(['project_id' => $projectId, 'code' => $entity['initial_episode_code']])->field('id')->find();
                $episodeId = $episodeId['id'];
            }
        }
        // todo 存在设计缺陷，此处治标
        $realStepWorkflowId = model(StepWorkflowModel::class)
            ->field('source_id')
            ->where([
                'id' => $stepWorkflowId,
                'source_id' => ['neq', 0],
            ])
            ->find();
        $taskStepCategoryIds = array_column($task, 'step_category_id', 'step_category_id');
        $projectReviewWorkflowRelation = $this->getProjectStepReviewWorkflow([
            'project_id' => $projectId,
            'step_workflow_id' => $realStepWorkflowId['source_id'] ?? $stepWorkflowId,
            'step_id' => $stepId,
            'attr_str' => $attrStr,
        ]);

        //审批流查询
        $reviewFilter = ['id' => $projectReviewWorkflowRelation['review_workflow_id'], 'active' => "yes", 'is_deleted' => "no",];
        list($nodesData, $promoter, $reviewers,) = $this->getParsedWorkflow($reviewFilter);
        // 自己的用户信息
        $userInfo = teamones_request('teamones-im', 'user/get_my_user_info', null)['data'];
        $myself = model(UserModel::class)->field('id,name,email,phone,avatar,union_id')->find($userId);

        // 组装部门id列表 把任务的部门id放在数组开头
        $myDepartmentInfoList = $userInfo['department_info'] ?? [];
        // 当任务部门变动,当前人员若工序分类所在 当前人员依然可以提交
        $headmanDepartmentIdList = [];
        $departmentIdList = $taskStepCategoryIds; //我当前所在部门与任务部门的整合
        foreach ($myDepartmentInfoList as $myDepartmentInfoItem) {
            $stepCategoryIdList = explode(',', $myDepartmentInfoItem['step_category_ids']);
            if (empty(array_diff($taskStepCategoryIds, $stepCategoryIdList))) {
                $headmanDepartmentIdList[] = $myDepartmentInfoItem['id'];
            }
            if (!isset($departmentIdList[$myDepartmentInfoItem['id']])) {
                $departmentIdList[$myDepartmentInfoItem['id']] = $myDepartmentInfoItem['id'];
            }
        }

        // 审核流需要的角色列表查询
        $reviewerRoles = array_column($reviewers, 'role');
        $requestData = ["param" => [
            "filter" => [
                "role.code" => ['-in', implode(',', $reviewerRoles)]
            ],
            "fields" => "role.id,role.name,role.code",
        ]];
        $roleInfo = teamones_request('teamones-im', 'role/select', $requestData)['data'];
        $roleInfo = $roleInfo['rows'] ?? [];
        if (empty($roleInfo)) {
            throw new LogicException("has not enough users to execute step check workflow", ErrorCode::NOT_ENOUGH_USERS_TO_EXECUTE_STEP_CHECK_WORKFLOW);
        }

        $roleNameMap = array_column($roleInfo, 'name', 'code');
        $roleCodeKeys = array_keys($roleNameMap);
        // 远端获取租户用户和角色信息
        $users = TenantService::getInstance()->selectTenantUser([
            "param" => [
                "filter" => [
                    "role.code" => ["-in", implode(',', $reviewerRoles)]
                ],
                "fields" => "id,user_id,role_id,tenant_id,department_id,role.name as role_name,role.code as role_code,department.step_category_ids",
                "page" => [1, C("database.database_max_select_rows")]
            ]
        ]);
        if (empty($users)) {
            throw new LogicException("has not enough users to execute step check workflow", ErrorCode::NOT_ENOUGH_USERS_TO_EXECUTE_STEP_CHECK_WORKFLOW);
        }
        //通过部门分组用户

        $usersGroupByDepartment = [];
        foreach ($users as $userIndex => &$user) {
            $user['role_code'] = [];
            if (!empty($user['role_info'])) {
                $user['role_code'] = array_column($user['role_info'], 'code');
            }
            foreach ($user['department_info'] as $department) {
                $usersGroupByDepartment[$department['id']][] = $users[$userIndex];
            }
        }
        $extraUserIdList = [];
        //导演  查询剧集分配
        $episodeAllocation = model(EpisodeAllocationModel::class)->where([
            'project_id' => $projectId,
            'role_code' => ["IN", implode(',', $reviewerRoles)],
            'entity_id' => $episodeId
        ])->select();
        $episodeAllocationGroupedByRole = [];
        if (!empty($episodeAllocation)) {
            $extraUserIdList = array_column($episodeAllocation, 'user_id', 'user_id');
            $episodeAllocationGroupedByRole = array_group_by($episodeAllocation, 'role_code');
        }
        $reviewPreSetConfig = $projectReviewWorkflowRelation['review_node_config'] ?? [];
        if (!empty($reviewPreSetConfig)) {
            $reviewPreSetConfigUserIdList = array_column($reviewPreSetConfig, 'user_id', 'user_id');
            $reviewPreSetConfig = array_column($reviewPreSetConfig, 'user_id', 'role_code');
            $extraUserIdList += $reviewPreSetConfigUserIdList;
        }
        $extraUserList = [];
        if (!empty($extraUserIdList)) {
            $extraUserList = model(UserModel::class)->where(['id' => ['IN', array_values($extraUserIdList)]])->field('id,name,avatar,phone,email')->select();
            $extraUserList = array_column($extraUserList, null, 'id');
        }

        $reviewersData = [];
        $reviewerSearchedIndex = -1;
        foreach ($reviewerRoles as $roleIndex => $role) {
            $tmpReviewerData = [
                'role_name' => $roleNameMap[$role],
                "role_code" => $role,
                "user_info" => [],
                "skip" => 0,
                'user_id' => 0,
            ];
            $presetUserId = $reviewPreSetConfig[$role] ?? 0;
            // 如果角色匹配的时候 跳过了当前角色 就设置审核人为当前用户 自动跳过
            if ($roleIndex <= $reviewerSearchedIndex) {
                REVIEW_SKIP:
                $tmpReviewerData['user_info'][] = $myself;
                $tmpReviewerData['skip'] = 1;
                // 自动跳过能跳过的节点 不需要匹配u用户  直接使用saas user
                $reviewersData[] = $tmpReviewerData;
                continue;
            }

            // 配置了指定的人员去审核
            if ($presetUserId > 0 && isset($extraUserList[$presetUserId])) {
                // 如果当前角色code为组长 而且配置的人员 是我自己就跳过审核
                if ($role === TaskService::HEADMAN_CODE && $presetUserId == $userId) {
                    goto REVIEW_SKIP;
                }
                $tmpReviewerData['user_info'][] = $extraUserList[$presetUserId];
                $reviewersData[] = $tmpReviewerData;
                continue;
            }

            $reviewerUsers = [];
            //处理特殊情况
            switch ($role) {
                case TaskService::HEADMAN_CODE:
                    APP_DEBUG && trace("开始在我所在的部门里寻找组长角色用户", 'DEBUG');
                    // 用map存储用户信息 根据user_id进行索引去重
                    $tmpUsersMap = [];
                    foreach ($headmanDepartmentIdList as $departmentId) {
                        array_map(function ($item) use ($role, &$tmpUsersMap) {
                            if (in_array($role, $item['role_code'])) {
                                $tmpUsersMap[$item['user_id']] = $item;
                            }
                        }, $usersGroupByDepartment[$departmentId] ?? []);
                    }
                    // 重新索引array 移除key
                    if (!empty($tmpUsersMap)) {
                        $reviewerUsers = array_values($tmpUsersMap);
                    }
                    break;
                case TaskService::PRODUCER_CODE:
                    //制片人  直接找制片人
                    APP_DEBUG && trace("开始全公司里寻找制片角色用户", 'DEBUG');
                    $reviewerUsers = array_filter($users, function ($item) use ($role) {
                        return in_array($role, $item['role_code']);
                    });
                    break;
                case TaskService::DIRECTOR_CODE:
                    // 导演 从租户里查
                    $reviewerUsers = array_filter($users, function ($item) use ($role) {
                        return in_array($role, $item['role_code']);
                    });
                    break;
                case TaskService::QA_CODE:
                case TaskService::ARTILIST_CODE:
                    //艺术家或者其他角色 直接进默认
                default:
                    // 默认处理 优先检查剧集分配数据 中是否包含
                    // 当前任务实体是否存在初始集
                    if (!empty($episode)) {
                        APP_DEBUG && trace("[default] 开始在剧集分配信息里里寻找{$role}角色用户", 'DEBUG');
                        //导演  查询剧集分配
                        $episodeAllocationList = $episodeAllocationGroupedByRole[$role] ?? [];
                        if (!empty($episodeAllocationList)) {
                            foreach ($episodeAllocationList as $episodeAllocation) {
                                if (isset($extraUserList[$episodeAllocation['user_id']])) {
                                    $tmpReviewerData['user_info'][] = $extraUserList[$episodeAllocation['user_id']];
                                }
                            }
                            if (count($tmpReviewerData['user_info']) > 0) {
                                $reviewersData[] = $tmpReviewerData;
                                continue 2;
                            }
                        }
                    }
                    APP_DEBUG && trace("[default] 开始在我所在的部门里寻找{$role}角色用户", 'DEBUG');
                    //优先从本部门查  然后在租户里查
                    foreach ($departmentIdList as $departmentId) {
                        $reviewerUsers = array_filter($usersGroupByDepartment[$departmentId] ?? [], function ($item) use ($role) {
                            return in_array($role, $item['role_code']);
                        });
                    }

                    if (empty($reviewerUsers)) {
                        //查不到用户 就从租户里查
                        APP_DEBUG && trace("[default] 开始在公司所有人里寻找{$role}角色用户", 'DEBUG');
                        $reviewerUsers = array_filter($users, function ($item) use ($role) {
                            return in_array($role, $item['role_code']);
                        });
                    }
            }
            if (empty($reviewerUsers)) {
                APP_DEBUG && trace("没有匹配到{$role}角色用户", 'DEBUG');
                throw new LogicException("can`t found a {$role}", ErrorCode::ROLE_NOT_FOUND);
            } else if (count($reviewerUsers) === 1) {
                $tmpReviewerData['user_info'][] = array_shift($reviewerUsers)['saas_user'];
            } else {
                $reviewerUsers = array_column($reviewerUsers, null, 'user_id');
                $tmpReviewerData['user_info'] = array_column($reviewerUsers, 'saas_user');
            }
            $reviewersData[] = $tmpReviewerData;
        }
        return [
            "review_workflow" => $nodesData,
            "matched_data" => [
                'promoter' => $promoter,
                'reviewers' => $reviewersData,
                'self_info' => $userInfo,
            ],
        ];
    }
}
